﻿using System;
using Garfield.Core;
using Garfield.Core.Runtime;
using Garfield.Core.Runtime.SPI;
using PicoContainer.Defaults;

namespace Garfield.Runtime.Pico
{
    public sealed class PlatformProvider : IPlatformProvider
    {
        private readonly DefaultPicoContainer serviceContext;
        private readonly ExtensionRegistry extensionRegistry;

        internal DefaultPicoContainer ServiceContext
        {
            get { return serviceContext; }
        }

        public PlatformProvider()
        {
            serviceContext = new DefaultPicoContainer(new ComponentAdapterFactory(this, true));
            extensionRegistry = new ExtensionRegistry(this,serviceContext);
            RegisterExtensionPoint(Platform.Services);
            serviceContext.RegisterComponentInstance(typeof (IExtensionRegistry), extensionRegistry);
            serviceContext.RegisterComponentInstance(typeof (IServiceLocator), new ServiceLocator(serviceContext));
            serviceContext.RegisterComponentInstance(typeof (IObjectFactory), new ObjectFactory(this));
        }

        public void RegisterExtensionPoint(Plugin.ExtensionPoint point)
        {
            var arguments = point.GetType().GetGenericArguments();
            var extensionPointType = (arguments.Length == 1 ? typeof (ExtensionPoint<>) : typeof (ExtensionPoint<,>)).MakeGenericType(arguments);
            if (extensionPointType == typeof(ExtensionPoint<Api, Implementation>))
            {
                extensionPointType = typeof (ExtensionPoint<Type, object>);
            }
            extensionRegistry.RegisterExtensionPoint(point.Identifier, point.IsCachingExtension, extensionPointType);
        }

        public void RegisterExtensionPoint<IdentifierType, ExtensionType>(string identifier, bool isCachingExtension)
        {
            extensionRegistry.RegisterExtensionPoint<IdentifierType, ExtensionType>(identifier, isCachingExtension);
        }

        public void RegisterExtensionPoint<ExtensionType>(string identifier, bool isCachingExtension)
        {
            extensionRegistry.RegisterExtensionPoint<ExtensionType>(identifier, isCachingExtension);
        }

        public void RegisterExtension(string extensionPointIdentifier, object identifier, object instance)
        {
            extensionRegistry.RegisterExtension(extensionPointIdentifier, identifier ?? Guid.NewGuid(), instance);
        }

        public void RegisterExtension(string extensionPointIdentifier, object identifier, Type implementation, Delegate initializer)
        {
            extensionRegistry.RegisterExtension(extensionPointIdentifier, identifier ?? Guid.NewGuid(), implementation, initializer);
        }

        public object GetService(Type api)
        {
            return serviceContext.GetComponentInstance(api);
        }

        public object GetExtensions(string extensionPointIdentifier)
        {
            return extensionRegistry.GetExtensions(extensionPointIdentifier);
        }
    }
}
